<template>
  <div class="knowledge-page">
    <div class="header">
      <h2>知识库</h2>
      <p>管理与检索知识内容。创建知识库后上传文档并完成向量化。</p>
    </div>

    <div class="toolbar">
      <el-input v-model="searchQuery" placeholder="搜索知识库..." clearable class="search-input" />
      <div class="spacer"></div>
    </div>

    <div class="grid">
      <!-- 新增知识库卡片 -->
      <div class="card add-card" @click="openCreateDialog">
        <div class="add-inner">
          <span class="plus">＋</span>
          <div class="add-text">新增知识库</div>
        </div>
      </div>

      <!-- 知识库卡片 -->
      <el-card
        v-for="kb in visibleKbs"
        :key="kb.id"
        class="card kb-card clickable"
        shadow="hover"
        @click="goDocs(kb.id)"
      >
        <div class="kb-title" :title="kb.name">{{ kb.name }}</div>
        <div class="kb-desc" v-if="kb.description">{{ kb.description }}</div>
        <div class="kb-meta">
          <span>文档数：{{ kb.document_count }}</span>
          <span class="time">创建：{{ formatTime(kb.created_at) }}</span>
        </div>
        <!-- 右下角省略号菜单 -->
        <div class="kb-more">
          <el-dropdown @click.stop trigger="click">
            <span class="el-dropdown-link" @click.stop>
              <el-icon><MoreFilled /></el-icon>
            </span>
            <template #dropdown>
              <el-dropdown-menu>
                <el-dropdown-item @click.stop="openEditKb(kb)">编辑</el-dropdown-item>
                <el-dropdown-item divided>
                  <el-popconfirm title="确认删除该知识库及其文档？" @confirm="onDelete(kb.id)">
                    <template #reference>
                      <span class="danger">删除</span>
                    </template>
                  </el-popconfirm>
                </el-dropdown-item>
              </el-dropdown-menu>
            </template>
          </el-dropdown>
        </div>
      </el-card>
    </div>

    <el-empty v-if="!loading && knowledgeBases.length === 0" description="暂无知识库" />

    <!-- 新建知识库对话框 -->
    <el-dialog v-model="createDialogVisible" title="新增知识库" width="480px">
      <el-form :model="createForm" label-width="84px">
        <el-form-item label="名称">
          <el-input v-model="createForm.name" maxlength="255" show-word-limit placeholder="请输入知识库名称" />
        </el-form-item>
        <el-form-item label="描述">
          <el-input v-model="createForm.description" type="textarea" :rows="3" placeholder="可选：简要描述" />
        </el-form-item>
        <el-form-item label="嵌入模型">
          <el-select v-model="createForm.embedding_model_name" placeholder="请选择嵌入模型" filterable style="width: 100%">
            <el-option v-for="m in embeddingModels" :key="m.model_name" :label="m.display_name || m.model_name" :value="m.model_name"/>
          </el-select>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="createDialogVisible = false">取消</el-button>
        <el-button type="primary" :loading="creating" @click="createKnowledge">创建</el-button>
      </template>
    </el-dialog>

    <!-- 编辑知识库对话框 -->
    <el-dialog v-model="editDialogVisible" title="编辑知识库" width="480px">
      <el-form :model="editForm" label-width="84px">
        <el-form-item label="名称">
          <el-input v-model="editForm.name" maxlength="255" show-word-limit placeholder="请输入知识库名称" />
        </el-form-item>
        <el-form-item label="描述">
          <el-input v-model="editForm.description" type="textarea" :rows="3" placeholder="可选：简要描述" />
        </el-form-item>
        <el-form-item label="嵌入模型">
          <el-select v-model="editForm.embedding_model_name" placeholder="请选择嵌入模型" filterable style="width: 100%">
            <el-option v-for="m in embeddingModels" :key="m.model_name" :label="m.display_name || m.model_name" :value="m.model_name"/>
          </el-select>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="editDialogVisible = false">取消</el-button>
        <el-button type="primary" :loading="updating" @click="updateKnowledge">保存</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script>
import { apiService } from '@/services/api'
import { MoreFilled } from '@element-plus/icons-vue'

export default {
  name: 'KnowledgeIndex',
  components: { MoreFilled },
  data() {
    return {
      loading: false,
      knowledgeBases: [],
      searchQuery: '',
      createDialogVisible: false,
      creating: false,
      createForm: {
        name: '',
        description: '',
        embedding_model_name: ''
      },
      editDialogVisible: false,
      updating: false,
      editForm: {
        id: null,
        name: '',
        description: '',
        embedding_model_name: ''
      },
      embeddingModels: []
    }
  },
  computed: {
    visibleKbs(){
      const q = (this.searchQuery || '').trim().toLowerCase()
      if (!q) return this.knowledgeBases
      return (this.knowledgeBases || []).filter(kb => {
        const n = (kb.name || '').toLowerCase()
        const d = (kb.description || '').toLowerCase()
        return n.includes(q) || d.includes(q)
      })
    }
  },
  mounted() {
    this.fetchKnowledgeBases()
    this.loadEmbeddingModels()
  },
  methods: {
    async fetchKnowledgeBases() {
      this.loading = true
      try {
        const res = await apiService.listKnowledgeBases(1, 50)
        this.knowledgeBases = res.knowledge_bases || []
      } catch (e) {
        console.error(e)
      } finally {
        this.loading = false
      }
    },
    openCreateDialog() {
      this.createDialogVisible = true
    },
    async createKnowledge() {
      if (!this.createForm.name.trim()) return
      this.creating = true
      try {
        const res = await apiService.createKnowledgeBase({
          name: this.createForm.name.trim(),
          description: this.createForm.description || '',
          embedding_model_name: this.createForm.embedding_model_name || null
        })
        this.createDialogVisible = false
        this.createForm = { name: '', description: '', embedding_model_name: '' }
        this.$message.success('创建成功')
        // 跳转到创建向导页并携带 kbId
        this.$router.push({ name: 'knowledge-create', query: { kbId: res.id } })
      } catch (e) {
        // ignore
      } finally {
        this.creating = false
      }
    },
    goDocs(kbId) {
      this.$router.push({ name: 'knowledge-documents', params: { kbId } })
    },
    async onDelete(kbId) {
      try {
        await apiService.deleteKnowledgeBase(kbId)
        this.$message.success('已删除')
        this.fetchKnowledgeBases()
      } catch (e) {
        // ignore
      }
    },
    openEditKb(kb) {
      this.editForm = { id: kb.id, name: kb.name, description: kb.description || '', embedding_model_name: kb.embedding_model_name || '' }
      this.editDialogVisible = true
    },
    async updateKnowledge() {
      if (!this.editForm.name.trim()) return
      this.updating = true
      try {
        await apiService.updateKnowledgeBase(this.editForm.id, {
          name: this.editForm.name.trim(),
          description: this.editForm.description || '',
          embedding_model_name: this.editForm.embedding_model_name || null
        })
        this.$message.success('已保存')
        this.editDialogVisible = false
        this.fetchKnowledgeBases()
      } catch (e) {
        // ignore
      } finally {
        this.updating = false
      }
    },
    async loadEmbeddingModels(){
      try{
        const res = await apiService.getModels('embedding')
        this.embeddingModels = res.models || []
      }catch(_){ /* ignore */ }
    },
    formatTime(t) {
      if (!t) return ''
      try {
        const d = new Date(t)
        return `${d.getFullYear()}-${(d.getMonth()+1).toString().padStart(2,'0')}-${d.getDate().toString().padStart(2,'0')}`
      } catch (_) {
        return t
      }
    }
  }
}
</script>

<style scoped>
.knowledge-page{
  padding: 24px;
  min-height: 0;
  box-sizing: border-box;
  --kb-accent: #4dabf7;
  --kb-accent-weak: rgba(77, 171, 247, 0.15);
  --kb-surface: linear-gradient(180deg, rgba(77,171,247,0.04), rgba(77,171,247,0.02));
  background: var(--kb-surface);
  width: 100%;
  max-width: none;
  margin: 0;
  font-size: 15px;
}
.header{
  padding: 12px 14px;
  border-radius: 12px;
  background: linear-gradient(180deg, rgba(77,171,247,0.08), rgba(77,171,247,0.02));
  border: 1px solid var(--kb-accent-weak);
  margin-bottom: 20px;
}
.header h2{
  font-size: 22px;
  margin-bottom: 6px;
  background-image: linear-gradient(120deg, rgba(77,171,247,0.35), rgba(77,171,247,0));
  background-size: 100% 40%;
  background-repeat: no-repeat;
  background-position: 0 80%;
}
.header p{
  color: var(--muted);
  font-size: 14px;
}
.toolbar{ display:flex; align-items:center; gap: 12px; margin: 12px 0 8px; }
.search-input{ max-width: 320px; }
.grid{ display: grid; grid-template-columns: repeat(5, minmax(220px, 1fr)); gap: 16px; }
.card{
  border-radius: 12px;
  transition: transform .24s cubic-bezier(.2,.7,.3,1), box-shadow .24s cubic-bezier(.2,.7,.3,1), border-color .24s cubic-bezier(.2,.7,.3,1), background-color .24s cubic-bezier(.2,.7,.3,1);
}
.clickable{ cursor: pointer; }
.add-card{
  border: 2px dashed var(--el-border-color);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 160px;
  transition: all .24s cubic-bezier(.2,.7,.3,1);
  background: var(--el-fill-color-light);
}
.add-card:hover{
  background: var(--kb-accent-weak);
  border-color: var(--kb-accent);
}
.add-inner{
  text-align: center;
  color: var(--el-text-color-regular);
}
.plus{
  font-size: 30px;
  line-height: 1;
  transition: transform .24s cubic-bezier(.2,.7,.3,1);
}
.add-card:hover .plus{ transform: scale(1.08); }
.add-text{
  margin-top: 6px;
  font-size: 13px;
  font-weight: 700;
}
.kb-card{
  height: 180px;
  min-height: 0;
  position: relative;
  border: 1px solid var(--el-border-color);
  overflow: hidden;
}
.kb-card::before{
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0; height: 4px;
  background: linear-gradient(90deg, rgba(77,171,247,.6), rgba(77,171,247,0));
}
.kb-card:hover{
  transform: translateY(-2px);
  box-shadow: 0 10px 26px rgba(64, 158, 255, 0.15);
  border-color: var(--kb-accent);
}
.kb-card:focus-within{ outline: none; box-shadow: 0 0 0 3px rgba(77,171,247,0.16); }
.kb-card:active{ transform: translateY(-1px); }
.kb-card :deep(.el-card__body){
  padding: 18px 18px 56px;
  display: flex;
  flex-direction: column;
}
.kb-title{
  font-weight: 900;
  font-size: 18px;
  line-height: 1.35;
  margin-bottom: 10px;
  color: var(--el-text-color-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  letter-spacing: .3px;
}
.kb-desc{
  color: var(--el-text-color-secondary);
  font-size: 14px;
  line-height: 1.7;
  margin-bottom: 4px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.kb-meta{
  margin-top: auto;
  padding-top: 6px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  color: var(--el-text-color-secondary);
  font-size: 13px;
  line-height: 1.5;
  font-variant-numeric: tabular-nums;
}
.kb-meta span{
  background: transparent;
  padding: 0;
  border-radius: 0;
  border: 0;
  font-weight: 500;
  box-shadow: none;
}
.kb-meta .time{ opacity: .9; }
.kb-more{
  position: absolute;
  right: 10px;
  top: 10px;
  bottom: auto;
  z-index: 2;
}
.kb-more :deep(.el-dropdown-link){
  display: inline-flex;
  width: 32px;
  height: 32px;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--el-fill-color);
  border: 1px solid var(--el-border-color);
  color: var(--el-text-color-secondary);
  box-shadow: 0 2px 10px rgba(64, 158, 255, 0.08);
  transition: background-color .22s ease, border-color .22s ease, color .22s ease, box-shadow .22s ease, transform .22s ease;
  cursor: pointer;
}
.kb-card:hover .kb-more :deep(.el-dropdown-link){
  border-color: var(--kb-accent);
  color: var(--kb-accent);
  box-shadow: 0 6px 16px rgba(64, 158, 255, 0.16);
}
.kb-more :deep(svg){ font-size: 16px; }
.danger{ color: var(--el-color-danger); }

/* Subtle page fade and card stagger */
.header{ animation: fadeUp .36s ease both; }
.grid .card{ animation: fadeUp .4s ease both; }
.grid .card:nth-child(1){ animation-delay: .02s; }
.grid .card:nth-child(2){ animation-delay: .04s; }
.grid .card:nth-child(3){ animation-delay: .06s; }
.grid .card:nth-child(4){ animation-delay: .08s; }
.grid .card:nth-child(5){ animation-delay: .10s; }

@keyframes fadeUp{
  from{ opacity: 0; transform: translateY(6px); }
  to{ opacity: 1; transform: translateY(0); }
}

/* Dialog header accent */
:deep(.el-dialog__header){
  border-bottom: 1px solid var(--kb-accent-weak);
}

/* Responsive grid */
@media (max-width: 1400px){ .grid{ grid-template-columns: repeat(4, minmax(220px, 1fr)); } }
@media (max-width: 1100px){ .grid{ grid-template-columns: repeat(3, minmax(220px, 1fr)); } }
@media (max-width: 820px){ .grid{ grid-template-columns: repeat(2, minmax(220px, 1fr)); } }
@media (max-width: 560px){ .grid{ grid-template-columns: 1fr; } }

/* AI-style buttons in dialogs */
.knowledge-page :deep(.el-dialog__footer .el-button){
  background-color: var(--accent, var(--kb-accent));
  border: none;
  color: #ffffff;
  box-shadow: 0 6px 18px rgba(61,85,236,.25);
}
.knowledge-page :deep(.el-dialog__footer .el-button:hover){ filter: brightness(1.05); }
.knowledge-page :deep(.el-dialog__footer .el-button.is-link){
  background-color: var(--accent, var(--kb-accent));
  color: #ffffff;
  padding: 6px 12px;
  border-radius: 6px;
}

</style>

